package py.com.alfa.escriba.web.services.impl;

import java.util.List;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;

import py.com.alfa.escriba.exception.ErrorCode;
import py.com.alfa.escriba.exception.ServiceException;
import py.com.alfa.escriba.persistence.dao.FuncionalidadDAO;
import py.com.alfa.escriba.persistence.dao.PerfilDAO;
import py.com.alfa.escriba.persistence.dao.PerfilFuncionalidadDAO;
import py.com.alfa.escriba.persistence.dto.admin.FuncionalidadDTO;
import py.com.alfa.escriba.persistence.dto.admin.PerfilDTO;
import py.com.alfa.escriba.persistence.dto.admin.PerfilFuncionalidadDTO;
import py.com.alfa.escriba.web.interceptor.InvocationContext;
import py.com.alfa.escriba.web.services.PerfilService;

public class PerfilServiceImpl implements PerfilService{

	private PerfilDAO perfilDAO;
	private PerfilFuncionalidadDAO perfilFuncionalidadDAO;
	private FuncionalidadDAO funcionalidadDAO;

	public void setPerfilDAO(PerfilDAO perfilDAO) {
		this.perfilDAO = perfilDAO;
	}

	@Override
	public List<PerfilDTO> listPerfil(InvocationContext ic) throws ServiceException {
		List<PerfilDTO> perfils =  perfilDAO.listPerfil();
		
		if (perfils == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"perfil.notfound");
		//carga de funcionalidades no asignadas
		for(PerfilDTO p: perfils){
			p.setFuncNoAsignadas(this.funcionalidadDAO.listFuncNoAsignadas(p.getId()));
		}

		return perfils;
	}

	@Override
	public PerfilDTO getPerfil(Long id, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		PerfilDTO perfil =  perfilDAO.getPerfilById(id);

		if (perfil == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"perfil.notfound", id);
		
		perfil.setFuncNoAsignadas(this.funcionalidadDAO.listFuncNoAsignadas(perfil.getId()));

		return perfil;
	}

	@Override
	public void deletePerfil(Long id, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		PerfilDTO perfil =  perfilDAO.getPerfilById(id);

		if(perfil == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"perfil.notfound", id);

		try {
			//TODO eliminar de perfil_funcionalidades
			
			perfilDAO.deletePerfil(perfil);
		}
		catch (DataIntegrityViolationException e){
			throw new ServiceException(ErrorCode.DATA_INTEGRITY_VIOLATION, "perfil.constraint.violation", id);
		}

	}

	@Override
	public PerfilDTO updatePerfil(Long id, PerfilDTO dto, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		if (null == dto)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","dto");

		PerfilDTO perfil = perfilDAO.getPerfilById(id);

		if (perfil == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"perfil.notfound", id);


		if(dto.getDescripcion() != null)
			perfil.setDescripcion(dto.getDescripcion());

		try{
			perfilDAO.updatePerfil(perfil);
		}catch (Exception e){
			throw new ServiceException(ErrorCode.INTERNAL_ERROR, "perfil.duplicate.key");
		}
		
		if(dto.getEliminar() != null){
			if(dto.getEliminar().getFuncionalidades() != null){
				PerfilFuncionalidadDTO pf = new PerfilFuncionalidadDTO();
				for(FuncionalidadDTO f: dto.getEliminar().getFuncionalidades()){
					pf.setIdFuncionalidad(f.getId());
					pf.setIdPerfil(dto.getId());
					try{
						this.perfilFuncionalidadDAO.deletePerfilFuncionalidad(pf);
					}catch (Exception e){
						throw new ServiceException(ErrorCode.INTERNAL_ERROR, "perfilfuncionalidad.constraint.violation", f.getId(), dto.getId());
					}
					pf = new PerfilFuncionalidadDTO();
				}
			}
		}

		if(dto.getAgregar() != null){
			if(dto.getAgregar().getFuncionalidades() != null){
				PerfilFuncionalidadDTO pf = new PerfilFuncionalidadDTO();
				PerfilFuncionalidadDTO pfPadre = new PerfilFuncionalidadDTO();
				for(FuncionalidadDTO f: dto.getAgregar().getFuncionalidades()){
					pf.setIdFuncionalidad(f.getId());
					pf.setIdPerfil(dto.getId());
					//verificar si la funcionalidad ya existe para el perfil
					PerfilFuncionalidadDTO pfDTO = this.perfilFuncionalidadDAO.getPerfilFuncionalidad(pf);
					try{
						if(pfDTO == null){
							this.perfilFuncionalidadDAO.createPerfilFuncionalidad(pf);
							//si se agrega una funcionalidad y tiene padre, el padre tambien deberia asignarse si no esta asignado aun al perfil
							if(f.getIdPadre() != null){
								pfPadre.setIdFuncionalidad(f.getIdPadre());
								pfPadre.setIdPerfil(dto.getId());
								//verificar si la funcionalidad padre ya existe para el perfil
								PerfilFuncionalidadDTO pfPadreDTO = this.perfilFuncionalidadDAO.getPerfilFuncionalidad(pfPadre);
								if(pfPadreDTO == null){
									this.perfilFuncionalidadDAO.createPerfilFuncionalidad(pfPadre);
								}
							}
							
						}
					}catch (Exception e){
						throw new ServiceException(ErrorCode.INTERNAL_ERROR, "perfilfuncionalidad.duplicate.key", f.getId(), dto.getId());
					}
					pf = new PerfilFuncionalidadDTO();
				}
			}
		}

		return perfil;
	}
	@Override
	public PerfilDTO createPerfil(PerfilDTO dto, InvocationContext ic) throws ServiceException {
		if (dto == null)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","dto");

		try {
			perfilDAO.createPerfil(dto);
			//guardar funcionalidades
			if(dto.getFuncAsignadas() != null && !dto.getFuncAsignadas().isEmpty()){
				PerfilFuncionalidadDTO pfDto = new PerfilFuncionalidadDTO();
				PerfilFuncionalidadDTO pfPadre = new PerfilFuncionalidadDTO();
				
				for(FuncionalidadDTO f: dto.getFuncAsignadas()){
					pfDto.setIdPerfil(dto.getId());
					pfDto.setIdFuncionalidad(f.getId());
					perfilFuncionalidadDAO.createPerfilFuncionalidad(pfDto);
					
					//si se agrega una funcionalidad y tiene padre, el padre tambien deberia asignarse si no esta asignado aun al perfil
					if(f.getIdPadre() != null){
						pfPadre.setIdFuncionalidad(f.getIdPadre());
						pfPadre.setIdPerfil(dto.getId());
						//verificar si la funcionalidad padre ya existe para el perfil
						PerfilFuncionalidadDTO pfPadreDTO = this.perfilFuncionalidadDAO.getPerfilFuncionalidad(pfPadre);
						if(pfPadreDTO == null){
							this.perfilFuncionalidadDAO.createPerfilFuncionalidad(pfPadre);
						}
					}
					
					pfDto = new PerfilFuncionalidadDTO();
					pfPadre =new PerfilFuncionalidadDTO();
				}
			}
		}
		catch (DuplicateKeyException e){
			throw new ServiceException(ErrorCode.DUPLICATE_KEY_EXCEPTION, "perfil.duplicate.key");
		}

		return dto;
	}

	public PerfilFuncionalidadDAO getPerfilFuncionalidadDAO() {
		return perfilFuncionalidadDAO;
	}

	public void setPerfilFuncionalidadDAO(
			PerfilFuncionalidadDAO perfilFuncionalidadDAO) {
		this.perfilFuncionalidadDAO = perfilFuncionalidadDAO;
	}

	public PerfilDAO getPerfilDAO() {
		return perfilDAO;
	}

	public FuncionalidadDAO getFuncionalidadDAO() {
		return funcionalidadDAO;
	}

	public void setFuncionalidadDAO(FuncionalidadDAO funcionalidadDAO) {
		this.funcionalidadDAO = funcionalidadDAO;
	}

}